#include "stdafx.h"
#include "SourceManager.h"
#include <boost/filesystem.hpp>
#include <fstream>

LUA_DEBUG_BEGIN

/**
* @brief Change the locale temporary.
*/
class scoped_locale
{
    std::locale m_prev;

public:
    explicit scoped_locale(const std::locale &loc) {
        m_prev = std::locale::global(loc);
    }

    ~scoped_locale() {
        std::locale::global(m_prev);
    }
};

/*-----------------------------------------------------------------*/
Source::Source(const std::string &key, const std::string &title,
               const string_array &sources, const std::string &path)
               : m_key(key), m_title(title), m_path(path), m_sources(sources) {
}

Source::Source() {
}

Source::~Source() {
}

/*-----------------------------------------------------------------*/
SourceManager::SourceManager(RemoteEngine_ptr engine) :
m_engine(engine),
m_textCounter(0)
{
    assert(engine != NULL);
}

SourceManager::~SourceManager() {
}

std::list<Source> SourceManager::GetList() {
    std::list<Source> result;

    ImplMap::iterator it;
    for (it = m_sourceMap.begin(); it != m_sourceMap.end(); ++it) {
        result.push_back(it->second);
    }

    return result;
}

const Source *SourceManager::Get(const std::string &key) {
    ImplMap::iterator it = m_sourceMap.find(key);
    if (it == m_sourceMap.end()) {
        return NULL;
    }

    return &(it->second);
}

const Source *SourceManager::GetString(const std::string &key) {
    std::list<Source> result;

    ImplMap::iterator it;
    for (it = m_sourceMap.begin(); it != m_sourceMap.end(); ++it) {
        if (it->second.GetKey().find(key) == 0) {
            return &(it->second);
        }
    }

    return NULL;
}

int SourceManager::AddSource(const Source &source, bool sendRemote) {
    m_sourceMap.insert(std::make_pair(source.GetKey(), source));

    if (sendRemote) {
        RemoteEngine_ptr p = m_engine.lock();
        if (p != NULL) {
            p->SendAddedSource(source);
        }
    }

    return 0;
}

static string_array split_line(std::istream &stream) {
    string_array array;
    char buffer[512];

    // Split each line.
    while (!stream.eof()) {
        stream.getline(buffer, sizeof(buffer));
        array.push_back(buffer);
    }

    return array;
}

int SourceManager::Add(const std::string &key, const std::string &src) {
    if (key.empty() || src.empty()) {
        return -1;
    }

    if (m_sourceMap.find(key) != m_sourceMap.end()) {
        return 0;
    }

    // It's a file if the beginning char is '@'.
    if (key[0] == '@') {
        boost::filesystem::path path(src);
        path = boost::filesystem::complete(path);
        path = path.normalize();
#if defined(BOOST_FILESYSTEM_VERSION) && (BOOST_FILESYSTEM_VERSION >= 3) // boost 1.51
        std::string pathstr = path.string();
#else
        std::string pathstr = path.native_file_string();
#endif

        scoped_locale sloc(std::locale(""));
        std::ifstream ifs(pathstr.c_str());
        if (!ifs.is_open()) {
            return -1;
        }

#if defined(BOOST_FILESYSTEM_VERSION) && (BOOST_FILESYSTEM_VERSION >= 3) // boost 1.51
        AddSource(Source(key, path.leaf().string(), split_line(ifs), pathstr), true);
#else
        AddSource(Source(key, path.leaf(), split_line(ifs), pathstr), true);
#endif
    }
    else {
        // We make the original source title and don't use the key,
        // because it may be too long.
        std::stringstream title;
        title << "<string: " << m_textCounter++ << ">";
        title.flush();

        std::stringstream sstream(src);
        AddSource(Source(key, title.str(), split_line(sstream)), true);
    }

    return 0;
}

int SourceManager::Save(const std::string &key, const string_array &source) {
    // Find the source from key.
    ImplMap::iterator it = m_sourceMap.find(key);
    if (it == m_sourceMap.end()) {
        return -1;
    }

    Source &src = it->second;
    if (src.GetPath().empty()) {
        return -1;
    }

    // Save the new source.
    scoped_locale sloc(std::locale(""));
    std::ofstream fp(src.GetPath().c_str());
    if (fp.fail()) {
        return -1;
    }

    for (string_array::size_type i = 0; i < source.size(); ++i) {
        const std::string &line = source[i];

        if (i > 0) {
            fp << std::endl;
        }

        fp << line;
    }

    return 0;
}

LUA_DEBUG_END
